package TAIC.IPLM;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Scanner;

import javax.imageio.ImageIO;
import javax.imageio.stream.FileImageOutputStream;
import static java.lang.Math.*;

public class GetImagePatches {
	public final static int R = 7 ; 
	public static void main ( String args [] ) throws Exception{
		if ( args.length != 2 ) {
			System.out.println ( "please input the corresponding file and the cluster result" ); 
			return ;
		}
		( new GetImagePatches()).work ( args ) ;	
	}
	
	public void work ( String args [] ) throws Exception {
		Scanner scanner = new Scanner ( new File ( "train.mat" )) ;
		int lines = scanner.nextInt () ;
		scanner.close () ; 
		String dir = "codeDir\\" ; 
		makeDir ( dir ) ;
		makeDir ( dir + "codes\\" ) ;
		Node[] count = new Node [ 800 ];
		for ( int i = 0 ;i < 800 ; i ++ ) {
			makeDir ( dir + i + "\\" ) ; 
			count [ i ] = new Node ( i ) ;
		}
		Scanner corScanner = new Scanner ( new File ( args [ 0 ] )) ;
		Scanner cluScanner = new Scanner ( new File ( args [ 1 ] )) ;
		String lastFile = "" ;
		BufferedImage img = null ;
		int line = 0 ; 
		while ( corScanner.hasNext() ) {
			String thisFile = corScanner.next() ;
			int cluster = cluScanner.nextInt() ;
			thisFile = thisFile.substring( 0, thisFile.lastIndexOf('.') ) ;
			if ( FileExists ( dir + cluster + "\\" + count [ cluster ].count + ".jpg" ) ) { 
				LoadImage ( dir + cluster + "\\" + count [ cluster ].count + ".jpg", count [ cluster ] ) ;
				count [cluster ].count ++ ; 
			}
			else {
				if ( ! thisFile.equals( lastFile) ) img = getImg ( thisFile ) ;
				if ( img != null ) {
					lastFile = thisFile ; 
					corScanner.next() ;
					double y = corScanner.nextDouble() ;
					double x = corScanner.nextDouble() ;
					corScanner.nextDouble () ; 
					double alpha = corScanner.nextDouble() ; 
					savePatch ( img, x, y, alpha, count [ cluster ], dir + cluster + "\\" + count [ cluster ].count + ".jpg") ;
					count [ cluster ].count ++ ; 
				}
			}
			corScanner.nextLine() ;
			if ( ++line % 10000 == 0 ) {
				System.out.printf ( "Complete percentage: %.2f" , (double)line * 100 / lines ) ;
				System.out.println ( "%" ) ;
			}
		//	if ( line > 20000 ) break ; 
		}		
		Arrays.sort( count ) ;
		PrintStream fout = new PrintStream ( new File ( dir + "\\stat.txt"  ) );
		for ( Node n : count ) fout.println ( n.index + "\t" + n.count ) ;
		fout.close() ;
		for ( int i = 0 ; i < 800; i ++ ) writeImage ( count[ i ], dir + "codes\\" + i + ".jpg" ) ;
	}
	
	private BufferedImage getImg ( String fileName ) throws Exception {
		try {
			BufferedImage img = ImageIO.read(new File( fileName ));
			return img ; 	
			
		} catch ( Exception e ) {
			System.out.println ( "Turning to grayScale image error: " + fileName ) ;
			return null; 
		}
	}
	
	private void LoadImage ( String FileName, Node n ) {
		try{
			BufferedImage bi = ImageIO.read( new File ( FileName ) ) ;
			int w = bi.getWidth();
			int h = bi.getHeight();
			for ( int i = 0 ; i < w ; i ++ ) 
				for ( int j = 0 ; j < h ; j ++ )  addColor ( n, i ,j, bi.getRGB( i,  j)) ;
		}
		catch ( Exception e ) {
			System.out.println ( "Load image error: " + FileName ) ;  
		}
	}
	
	private void savePatch ( BufferedImage img, double dx, double dy, double alpha, Node n, String fileName ) throws Exception{
		int x = (int) Math.floor( dx );
		int y = (int) Math.floor( dy );
		int w = img.getWidth(null) ;   // x dim
		int h = img.getHeight(null);   // y dim
		
		int iR = (int) Math.ceil( Math.sqrt(2) * R ) ; 
		BufferedImage image = new BufferedImage(
				2 * iR +  1,
				2 * iR +  1,
				BufferedImage.TYPE_3BYTE_BGR
				);
		
		int i1 = limit ( 0, w , x - R ) ;
		int i2 = limit ( 0, w , x + R ) ;
		int j1 = limit ( 0, h , y - R ) ;
		int j2 = limit ( 0, h , y + R ) ;
		
		for ( int i = i1 ; i <= i2 ; i ++ )
			for ( int j = j1; j <= j2 ; j ++ ) {
				int px = i - x ; 
				int py = j - y ;  
				double r = sqrt ( px * px + py * py ) ;
				double angle = acos ( px / r ) ;
				if ( py < 0 ) angle = - angle ;
				 angle += alpha ; 
					
				image.setRGB( 
						(int) floor(iR + cos ( angle ) * r ), 
						(int) floor(iR + sin ( angle ) * r ), 
						img.getRGB( i, j)
						) ;
				addColor ( n, (int) floor(iR + cos ( angle ) * r ), (int) floor(iR + sin ( angle ) * r ), img.getRGB(i,j) ) ;
			}
		ImageIO.write( image , "jpg", new FileImageOutputStream ( new File ( fileName )));
	}

	private void addColor ( Node n, int i, int j , int color ) {
		int r = ((int)(color >> 16))& 0xff ;
		int g = ((int)(color >> 8) )& 0xff ;
		int b = ((int)(color >> 0) )& 0xff ;
		n.R [ i ][ j ] += r ;
		n.G [ i ][ j ] += g ;
		n.B [ i ][ j ] += b ;
	}
	
	private void writeImage ( Node n, String fileName) throws Exception {
		int iR = (int) Math.ceil( Math.sqrt(2) * R ) ; 
		BufferedImage image = new BufferedImage(
				2 * iR +  1,
				2 * iR +  1,
				BufferedImage.TYPE_3BYTE_BGR 
				);
		for ( int i = 0 ; i < iR * 2 + 1; i ++) 
			for ( int j = 0 ; j < iR * 2 + 1; j ++ ) 
				image.setRGB( i, j, getColor ( n, i,j ));
		ImageIO.write( image , "jpg", new FileImageOutputStream ( new File ( fileName )));		
	}
	
	private int getColor ( Node n , int i , int j ) {
		int r = (int)(n.R[i][j]/(double)n.count);
		int g = (int)(n.G[i][j]/(double)n.count);
		int b = (int)(n.B[i][j]/(double)n.count);
		int x = (int) ( 0.3 * r + 0.59 * g + 0.11 * b ) ; 
		return (x << 16) + (x << 8) + x ; 
	}
	
	boolean FileExists ( String file ) {
		File f = new File ( file ) ;
		return f.exists() ; 
	}
		
	private int limit ( int low, int high, int value ) {
		if ( value < low ) return low;
		if ( value < high ) return value ;
		return high - 1  ;
	}
	
	private void makeDir ( String dirName ) {
		File dir = new File ( dirName ) ;
		if ( ! dir.exists() ) dir.mkdirs() ; 
	}	
}

class Node implements Comparable < Node >{
	public Node ( int index ) {
		this.index = index;
		int iR = (int) Math.ceil( Math.sqrt(2) * GetImagePatches.R ) * 2 + 1 ; 
		R = new int [ iR ][] ;
		G = new int [ iR ][] ;
		B = new int [ iR ][] ;
		for ( int i = 0 ; i < iR; i ++ ){
			R [ i ] = new int [ iR ] ; 
			G [ i ] = new int [ iR ] ; 
			B [ i ] = new int [ iR ] ; 			
		}
	}
	
	int index;
	int count;
	int [][] R ;
	int [][] G;
	int [][] B;
	
	public int compareTo ( Node n ) {
		if ( count > n.count ) return -1 ;
		else if ( count == n.count ) return 0 ;
		else return 1;
	}
}

